home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / general / modelers / geomview / source.lha / Geomview / doc / geomview-3 < prev    next >
Text File  |  1993-12-06  |  51KB  |  1,295 lines

  1. Info file: geomview,    -*-Text-*-
  2. produced by texinfo-format-buffer
  3. from file: geomview.tex
  4.  
  5.  
  6. 
  7. File: geomview  Node: GROUP, Prev: TLIST, Up: Object File Formats, Next: DISCGRP
  8.  
  9. GROUP Files
  10. -----------
  11.  
  12. This format is obsolete, but is still accepted.  It combined the
  13. functions of `INST' and `TLIST', taking a series of
  14. transformations and a single Geom (`unit') object, and replicating
  15. the object under each transformation.
  16.  
  17.      GROUP ... < matrices > ... unit { OOGL-OBJECT }
  18.  
  19. is still accepted and effectively translated into
  20.  
  21.      INST
  22.          transforms { TLIST ... <matrices> ... }
  23.          unit { OOGL-OBJECT }
  24.  
  25. 
  26. File: geomview  Node: DISCGRP, Prev: GROUP, Up: Object File Formats, Next: Non-geometric objects
  27.  
  28. DISCGRP Files
  29. -------------
  30.  
  31. This format is for discrete groups, such as appear in the theory of
  32. manifolds or in symmetry patterns.  This format has its own man page.
  33. See discgrp(5).
  34.  
  35. 
  36. File: geomview  Node: Non-geometric objects, Prev: DISCGRP, Up: OOGL File Formats, Next: transform
  37.  
  38. Non-geometric objects
  39. =====================
  40.  
  41.  
  42. The syntax of these objects is given in the form used in
  43. *Note References::, where "quoted" items should appear literally but
  44. without quotes, square bracketed ([ ]) items are optional, and | separates
  45. alternative choices.
  46.  
  47. * Menu:
  48.  
  49. * transform::    Transformation matrices.
  50. * camera::    Cameras.
  51. * window::    Windows.
  52.  
  53. 
  54. File: geomview  Node: transform, Prev: Non-geometric objects, Up: Non-geometric objects, Next: camera
  55.  
  56. Transform Objects
  57. -----------------
  58.  
  59. Where a single 4x4 matrix is expected -- as in the
  60. `INST' `transform' field, the camera's `camtoworld' transform
  61. and the Geomview `xform*' commands -- use a transform object.
  62.  
  63. Note that a transform is distinct from a `TLIST', which is a type
  64. of geometry.  `TLIST's can contain one or more 4x4 transformations;
  65. "transform" objects must have exactly one.
  66.  
  67. Why have both?  In many places -- e.g. camera positioning -- it's only
  68. meaningful to have a single transform.  Using a separate object type
  69. enforces this.
  70.  
  71. Syntax for a transform object is
  72.  
  73.      <transform> ::= 
  74.        [ "{" ]             (curly brace, generally needed to make
  75.                             the end of the object unambiguous.)
  76.  
  77.         [ "transform" ]    (optional keyword; unnecessary if the type
  78.                             is determined by the context, which it
  79.                             usually is.)
  80.         [ "define" <name> ]
  81.                            (defines a transform named <name>, setting
  82.                             its value from the stuff which follows)
  83.  
  84.            <sixteen floating-point numbers>
  85.                            (interpreted as a 4x4 homogeneous transform
  86.                     given row by row, intended to apply to a
  87.                             row vector multiplied on its LEFT, so that e.g.
  88.                             Euclidean translations appear in the bottom row)
  89.         | 
  90.            "<" <filename>  (meaning: read transform from that file)
  91.         |
  92.            ":" <name>      (meaning: use variable <name>,
  93.                              defined elsewhere; if undefined the initial
  94.                              value is the identity transform)
  95.  
  96.       [ "}" ]              (matching curly brace)
  97.  
  98. The whole should be enclosed in { braces }.  Braces are not essential
  99. if exactly one of the above items is present, so e.g. a 4x4 array of
  100. floats standing alone may but needn't have braces.
  101.  
  102. Some examples, in contexts where they might be used:
  103.  
  104.      # Example 1: A gcl command to define a transform
  105.      # called "fred"
  106.  
  107.      (read transform { transform  define fred
  108.               1 0 0 0
  109.               0 1 0 0
  110.               0 0 1 0
  111.              -3 0 1 1
  112.          }
  113.      )
  114.  
  115.      # Example 2:  A camera object using transform
  116.      # "fred" for camera positioning
  117.      # Given the definition above, this puts the camera at
  118.      # (-3, 0, 1), looking toward -Z.
  119.  
  120.      { camera
  121.              halfyfield 1
  122.              aspect 1.33
  123.              camtoworld { : fred }
  124.      }
  125.  
  126. 
  127. File: geomview  Node: camera, Prev: transform, Up: Non-geometric objects, Next: window
  128.  
  129. cameras
  130. -------
  131.  
  132. A camera object specifies the following properties of a camera:
  133.  
  134. position and orientation
  135.      specified by either a camera-to-world or world-to-camera transformation;
  136.      this transformation does not include the projection, so it's typically
  137.      just a combination of translation and rotation.  Specified as a
  138.      transform object, typically a 4x4 matrix.
  139. "focus" distance
  140.      Intended to suggest a typical distance from the camera to the object of
  141.      interest; used for default camera positioning (the camera is placed at
  142.      (X,Y,Z) = (0,0,focus) when reset) and for adjusting field-of-view when
  143.      switching between perspective and orthographic views.
  144. window aspect ratio
  145.      True aspect ratio in the sense <Xsize>/<Ysize>.  This normally should
  146.      agree with the aspect ratio of the camera's window.  Geomview normally
  147.      adjusts the aspect ratio of its cameras to match their associated
  148.      windows.
  149. near and far clipping plane distances
  150.      Note that both must be strictly greater than zero.  Very large
  151.      <far>/<near> distance ratios cause Z-buffering to behave badly; part of
  152.      an object may be visible even if somewhat more distant than another.
  153. field of view
  154.      Specified in either of two forms.
  155.             `fov '
  156.      
  157.           is the field of view -- in degrees if perspective, or linear
  158.           distance if orthographic -- in the *shorter* direction.
  159.             `halfyfield '
  160.      
  161.           is half the projected Y-axis field, in world coordinates (not angle!),
  162.           at unit distance from the camera.  For a perspective camera, halfyfield
  163.           is related to angular field:
  164.  
  165.                    halfyfield = tan( Y_axis_angular_field / 2 )
  166.  
  167.           while for an orthographic one it's simply:
  168.  
  169.                        halfyfield = Y_axis_linear_field / 2
  170.  
  171.  
  172.      This odd-seeming definition is (a) easy to calculate with and
  173.      (b) well-defined in both orthographic and perspective views.
  174.  
  175.  
  176. The syntax for a camera is:
  177.  
  178.      <camera> ::=
  179.  
  180.         [ "camera" ]            (optional keyword)
  181.          [ "{" ]            (opening brace, generally required)
  182.          [ "define" <name> ]
  183.  
  184.          "<" <filename>
  185.            |
  186.          ":" <name>
  187.            |
  188.                      (or any number of the following,
  189.                       in any order...)
  190.  
  191.          "perspective"  {"0" | "1"}        (default 1)
  192.                          (otherwise orthographic)
  193.  
  194.          "stereo"       {"0" | "1"}        (default 0)
  195.                          (otherwise mono)
  196.  
  197.          "worldtocam" <transform>    (see transform syntax above)
  198.  
  199.          "camtoworld" <transform>
  200.                      (no point in specifying both
  201.                       camtoworld and worldtocam; one is
  202.                       constrained to be the inverse of                         the other)
  203.  
  204.          "halfyfield" <half-linear-Y-field-at-unit-distance>
  205.                      (default tan 40/2 degrees)
  206.  
  207.          "fov"        (angular field-of-view if perspective,
  208.                   linear field-of-view otherwise.
  209.                   Measured in whichever direction is smaller,
  210.                   given the aspect ratio.  When aspect ratio
  211.                   changes -- e.g. when a window is reshaped --
  212.                   "fov" is preserved.)
  213.  
  214.          "frameaspect" <aspect-ratio>    (X/Y) (default 1.333)
  215.  
  216.          "near"  <near-clipping-distance>    (default 0.1)
  217.     
  218.          "far"    <far-clipping-distance>        (default 10.0)
  219.  
  220.          "focus" <focus-distance>        (default 3.0)
  221.  
  222.     
  223.           [ "}" ]                (matching closebrace)
  224.  
  225.  
  226. 
  227. File: geomview  Node: window, Prev: camera, Up: Non-geometric objects, Next: Customization
  228.  
  229. window
  230. ------
  231.  
  232. A window object specifies size, position, and other window-system
  233. related information about a window in a device-independent way.
  234.  
  235. The syntax for a window object is:
  236.  
  237.      window ::=
  238.  
  239.          [ "window" ]            (optional keyword)
  240.            [ "{" ]            (curly brace, often required)
  241.  
  242.                          (any of the following, in any order)
  243.  
  244.              "size"  <xsize> <ysize>
  245.                      (size of the window)
  246.  
  247.              "position"  <xmin> <xmax> <ymin> <ymax>
  248.                      (position & size)
  249.  
  250.  
  251.              "noborder"
  252.                      (specifies the window should
  253.                       have no window border)
  254.  
  255.              "pixelaspect"  <aspect>
  256.                      (specifies the true visual aspect ratio
  257.                       of a pixel in this window in the sense
  258.                       xsize/ysize, normally 1.0.
  259.                       For stereo hardware which stretches the
  260.                       display vertically by a factor of 2,
  261.                       "pixelaspect 0.5" might do.
  262.                       The value is used when computing the
  263.                       projection of a camera associated with
  264.                       this window.)
  265.  
  266.            [ "}" ]            (matching closebrace)
  267.  
  268. Window objects are used in the Geomview `window' and
  269. `ui-panel' commands to set default properties for future windows or
  270. to change those of an existing window.
  271.  
  272.  
  273. 
  274. File: geomview  Node: Customization, Prev: window, Up: Top, Next: Modules
  275.  
  276. Customization: `.geomview' files
  277. ********************************
  278.  
  279. When Geomview is started, it loads and executes commands in a
  280. system-wide startup file named `.geomview'.  This file is in the
  281. `data' subdirectory of the Geomview distribution directory
  282. `/u/gcg/ngrap/data' on the Geometry Center's computer system) and
  283. contains gcl commands to configure Geomview in a way
  284. common to all users on the system.
  285.  
  286. Next, Geomview looks for the file `~/.geomview' (`~'
  287. stands for your home directory).  You can use this to configure
  288. your own default Geomview behavior to suit your tastes.
  289.  
  290. After reading `~/.geomview', Geomview looks for a file named
  291. `.geomview' in the current directory.  If such a file exists
  292. Geomview reads it, unless it is the same as `~/.geomview' (which
  293. would be the case if you are running Geomview from your home directory).
  294. You can use the current directory's `.geomview' to create a Geomview
  295. customization specific to a certain project.
  296.  
  297. You can use `.geomview' files to control all kinds of things about
  298. Geomview.  They can contain any valid gcl statements.  Especially
  299. useful is the `ui-panel' command which controls the initial
  300. placement of Geomview's panels.  For an example see the system-wide
  301. `.geomview' file mentioned above.  For details of gcl,
  302. *Note GCL::.
  303.  
  304. It is a good idea to enclose all the commands you put in a
  305. `.geomview' file in a `progn' statement in order to cause
  306. Geomview to execute them all at once.  Otherwise Geomview might execute
  307. them sequentially over the first few refresh cycles after starting up.
  308.  
  309. 
  310. File: geomview  Node: Modules, Prev: Customization, Up: Top, Next: Interface
  311.  
  312. External Modules
  313. ****************
  314.  
  315. An external module is a program that interacts with Geomview.  A
  316. module communicates with Geomview through gcl and can
  317. control any apsect of Geomview that you can control through Geomview's
  318. user interface.
  319.  
  320. In many cases an external module is a specialized program that
  321. implements some mathematical algorithm that creates a geometric
  322. object that changes shape as the algorithm progresses.  The module
  323. informs Geomview of the new object shape at each step, so the object
  324. appears to evolve with time in the Geomview window.  In this way
  325. Geomview serves as a *display engine* for the module.
  326.  
  327. An external module may be interactive.  It can respond to mouse and
  328. keyboard events that take place in a Geomview window, thus extending
  329. the capability of Geomview itself.
  330.  
  331. * Menu:
  332.  
  333. * Interface::               How External Modules Interface with Geomview.
  334. * Example1::                Simple External Module.
  335. * Example2::                Simple External Module with FORMS Control Panel.
  336. * Forms::                   The FORMS Library.
  337. * Example3::                External Module with Bi-Directional Communication.
  338. * Module Installation::     Module Installation.
  339.  
  340. 
  341. File: geomview  Node: Interface, Prev: Modules, Up: Modules, Next: Example1
  342.  
  343. How External Modules Interface with Geomview
  344. ============================================
  345.  
  346. External modules appear in the *Modules* browser in Geomview's
  347. *Main* panel.  To run a module, click the left mouse button on
  348. the module's entry in the browser.  While the module is running, an
  349. additional line for that module will appear in red in the browser.
  350. This line begins with a number in brackets, which indicates the
  351. *instace* number of the module.  (For some modules it makes sense
  352. to have more than one instance of the module running at the same
  353. time.)  You can kill an external module by clicking on its red
  354. instance entry.
  355.  
  356. By default when Geomview starts, it displays all the modules that have
  357. been installed on your system. 
  358.  
  359. For instructions on installing a module on your system so that it will
  360. appear in the *Modules* browser every time Geomview is run by
  361. anyone on your system, *Note Module Installation::.
  362.  
  363. When Geomview invokes an external module, it creates pipes connected
  364. to the module's standard input and output. (Pipes are like files
  365. except they are used for communication between programs rather than
  366. for storing things on a disk.)  Geomview interprets anything that the
  367. module writes to its standard output as a gcl command.
  368. Likewise, if the exernal module requests any data from Geomview,
  369. Geomview writes that data to the module's standard input.  Thus all a
  370. module has to do in order to communicate with Geomview is write
  371. commands to standard output and (optionally) receive data on standard
  372. input.  Note that this means that the module cannot use standard input
  373. and output for communicating with the user.  If a module needs to
  374. communicate with the user it can do so either through a control
  375. panel of its own or else by responding to certain events that it finds
  376. out about from Geomview.
  377.  
  378. 
  379. File: geomview  Node: Example1, Prev: Interface, Up: Modules, Next: Example2
  380.  
  381. Example 1: Simple External Module
  382. =================================
  383.  
  384. This section gives a very simple external module which displays an
  385. oscillating mesh.  To try out this example, make a copy of the file
  386. `example1.c' (it is distributed with Geomview in the `doc'
  387. subdirectory) in your directory and compile it with the command
  388.  
  389.      cc -o example1 example1.c -lm
  390.  
  391. Then put the line
  392.  
  393.      (emodule-define "Example 1" "./example1")
  394.  
  395. in a file called `.geomview' in your current directory.  Then invoke
  396. Geomview; it is important that you compile the example program, create
  397. the `.geomview' file, and invoke Geomview all in the same
  398. directory.  You should see "Example 1" in the *Modules* browser
  399. of Geomview's *Main* panel; click on this entry in the browser to
  400. start the module.  A surface should appear in your camera window and should
  401. begin oscillating.  You can stop the module by clicking on the red "[1]
  402. Example 1" line in the *Modules* browser.
  403.  
  404.      /*
  405.       * example1.c: oscillating mesh
  406.       *
  407.       * This example module is distributed with the Geomview manual.
  408.       * If you are not reading this in the manual, see the "External
  409.       * Modules" chapter of the manual for more details.
  410.       *
  411.       * This module creates an oscillating mesh.
  412.       */
  413.  
  414.      #include <math.h>
  415.      #include <stdio.h>
  416.  
  417.      /* F is the function that we plot
  418.       */
  419.      float F(x,y,t)
  420.           float x,y,t;
  421.      {
  422.        float r = sqrt(x*x+y*y);
  423.        return(sin(r + t)*sqrt(r));
  424.      }
  425.  
  426.      main(argc, argv)        
  427.           char **argv;
  428.      {
  429.        int xdim, ydim;
  430.        float xmin, xmax, ymin, ymax, dx, dy, t, dt;
  431.  
  432.        xmin = ymin = -5;             /* Set x and y            */
  433.        xmax = ymax = 5;              /*    plot ranges         */
  434.        xdim = ydim = 24;             /* Set x and y resolution */
  435.        dt = 0.1;                     /* Time increment is 0.1  */
  436.  
  437.        /* Geomview setup.  We begin by sending the command
  438.         *            (geometry example { : foo})
  439.         * to Geomview.  This tells Geomview to create a geom called
  440.         * "example" which is an instance of the handle "foo".
  441.         */
  442.        printf("(geometry example { : foo })\n");
  443.        fflush(stdout);
  444.  
  445.        /* Loop until killed.
  446.         */
  447.        for (t=0; ; t+=dt) {
  448.          UpdateMesh(xmin, xmax, ymin, ymax, xdim, ydim, t);
  449.        }
  450.      }
  451.  
  452.      /* UpdateMesh sends one mesh iteration to Geomview.  This consists of
  453.       * a command of the form
  454.       *    (read geometry { define foo
  455.       *       MESH
  456.       *       ...
  457.       *    })
  458.       * where ... is the actual data of the mesh.  This command tells
  459.       * Geomview to make the value of the handle "foo" be the specified
  460.       * mesh.
  461.       */
  462.      UpdateMesh(xmin, xmax, ymin, ymax, xdim, ydim, t)
  463.           float xmin, xmax, ymin, ymax, t;
  464.           int xdim, ydim;
  465.      {
  466.        int i,j;
  467.        float x,y, dx,dy;
  468.  
  469.        dx = (xmax-xmin)/(xdim-1);
  470.        dy = (ymax-ymin)/(ydim-1);
  471.  
  472.        printf("(read geometry { define foo \n");
  473.        printf("MESH\n");
  474.        printf("%1d %1d\n", xdim, ydim);
  475.        for (j=0, y = ymin; j<ydim; ++j, y += dy) {
  476.          for (i=0, x = xmin; i<xdim; ++i, x += dx) {
  477.            printf("%f %f %f\t", x, y, F(x,y,t));
  478.          }
  479.          printf("\n");
  480.        }
  481.        printf("})\n");
  482.        fflush(stdout);
  483.      }
  484.  
  485. The module begins by defining a function `F(x,y,t)' that
  486. specifies a time-varying surface.  The purpose of the module is to
  487. animate this surface over time.
  488.  
  489. The main program begins by defining some variables that specify
  490. the parameters with which the function is to be plotted.
  491.  
  492. The next bit of code in the main program prints the following
  493. line to standard output
  494.  
  495.      (geometry example { : foo })
  496.  
  497. This tells Geomview to create a geom called `example' which is an
  498. instance of the handle `foo'.  *Handles* are a part of the
  499. OOGL file format which allow you to name a piece of geometry whose value
  500. can be specified elsewhere (and in this case updated many times); for
  501. more information on handles, *Note OOGL File Formats:: In this case,
  502. `example' is the title by which the user will see the object in
  503. Geomview's object browser, and `foo' is the internal name of the
  504. handle that the object is a reference to.
  505.  
  506. We then do `fflush(stdout)' to ensure that Geomview
  507. receives this command immediately.  In general, since pipes may be
  508. buffered, an external module should do this whenever it wants to be
  509. sure Geomview has actually received everything it has printed out.
  510.  
  511. The last thing in the main program is an infinite loop that cycles
  512. through calls to the procedure `UpdateMesh' with increasing
  513. values of `t'.  `UpdateMesh' sends Geomview a command
  514. of the form
  515.  
  516.      (read geometry { define foo 
  517.      MESH
  518.      24 24
  519.      ...
  520.      })
  521.  
  522. where `...' is a long list of numbers.  This command tells Geomview
  523. to make the value of the handle `foo' be the specified mesh.  As
  524. soon as Geomview receives this command, the geom being displayed
  525. changes to reflect the new geometry.
  526.  
  527. The mesh is given in the format of an OOGL MESH.  This begins with
  528. the keyword `MESH'.  Next come two numbers that give the x and y
  529. dimensions of the mesh; in this case they are both 24.  This line is
  530. followed by 24 lines, each containing 24 triples of numbers.  Each of
  531. these triples is a point on the surface.  Then finally there is a line
  532. with "`})'" on it that ends the "`{'" which began the
  533. `define' statement and the "`('" that began the command.  For
  534. more details on the format of MESH data, *Note MESH::.
  535.  
  536. This module could be written without the use of handles by having it
  537. write out commands of the form
  538.  
  539.      (geometry example {
  540.      MESH
  541.      24 24
  542.      ...
  543.      })
  544.  
  545. This first time Geomview receives a command of this form it would create
  546. a geom called `example' with the given `MESH' data.
  547. Subsequent `(geometry example ...)' commands would cause
  548. Geomview to replace the geometry of the geom `example' with the new
  549. `MESH' data.  If done in this way there would be no need to send
  550. the initial `(geometry example { : foo })' command as above.  The
  551. handle technique is useful, however, because it can be used in more
  552. general situations where a handle represents only part of a complex
  553. geom, allowing an external module to replace only that part without
  554. having to retransmit the entire geom.  For more information on handles,
  555. *Note GCL::.
  556.  
  557. The module loops through calls to `UpdateMesh' which print out
  558. commands of the above form one after the other as fast as possible.
  559. The loop continues indefinitely; the module will terminate when the
  560. user kills it by clicking on its instance line in the *Modules*
  561. browser, or else when Geomview exits.
  562.  
  563. Sometimes when you terminate this module by clicking on its instance
  564. entry the *Modules* browser, Geomview will kill it while it is in
  565. the middle of sending a command to Geomview.  Geomview will then receive
  566. only a piece of a command and will print out a cryptic but harmless
  567. error message about this.  When a module has a user interface panel
  568. it can use a "Quit" button to provide a more graceful way for the user
  569. to terminate the module.  See the next example.
  570.  
  571. You can run this module in a shell window without Geomview to see the
  572. commands it prints out.  You will have to kill it with
  573. `ctrl-C' to get it to stop.
  574.  
  575. 
  576. File: geomview  Node: Example2, Prev: Example1, Up: Modules, Next: Forms
  577.  
  578. Example 2: Simple External Module with FORMS Control Panel
  579. ==========================================================
  580.  
  581. This section gives a new version of the above module --- one that
  582. includes a user interface panel for controlling the velocity of the
  583. oscillation.  We use the FORMS library by Mark Overmars for the control
  584. panel.  The FORMS library is a public domain user interface toolkit for
  585. IRISes; for more information *Note Forms::.
  586.  
  587. To try out this example, make a copy of the file
  588. `example2.c' (distributed with Geomview in the `doc'
  589. subdirectory) in your directory and compile it with the command
  590.  
  591.      cc -I/u/gcg/ngrap/include -o example2 example2.c \
  592.        -L/u/gcg/ngrap/lib/sgi -lforms -lfm_s -lgl_s -lm
  593.  
  594. If you are not using the Geometry Center's computer system you should
  595. replace the string `/u/gcg/ngrap' above with the pathname of the
  596. Geomview distribution directory on your system.  (The forms library is
  597. distributed with Geomview and the `-I' and `-L' options above
  598. tell the compiler where to find it.)
  599.  
  600. Then put the line
  601.  
  602.      (emodule-define "Example 2" "./example2")
  603.  
  604. in a file called `.geomview' in the current directory and invoke
  605. Geomview from that directory.  Click on the "Example 2" entry in the
  606. *Modules* browser to invoke the module.  A small control panel
  607. should appear.  You can then control the velocity of the mesh
  608. oscillation by moving the slider.
  609.  
  610.      /*
  611.       * example2.c: oscillating mesh with FORMS control panel
  612.       *
  613.       * This example module is distributed with the Geomview manual.
  614.       * If you are not reading this in the manual, see the "External
  615.       * Modules" chapter of the manual for an explanation.
  616.       *
  617.       * This module creates an oscillating mesh and has a FORMS control
  618.       * panel that lets you change the speed of the oscillation with a
  619.       * slider.
  620.       */
  621.  
  622.      #include <math.h>
  623.      #include <stdio.h>
  624.      #include <sys/time.h>           /* for struct timeval below */
  625.  
  626.      #include "forms.h"              /* for FORMS library */
  627.  
  628.      FL_FORM *OurForm;
  629.      FL_OBJECT *VelocitySlider;
  630.      float dt;
  631.  
  632.      /* F is the function that we plot
  633.       */
  634.      float F(x,y,t)
  635.           float x,y,t;
  636.      {
  637.        float r = sqrt(x*x+y*y);
  638.        return(sin(r + t)*sqrt(r));
  639.      }
  640.  
  641.      /* SetVelocity is the slider callback procedure; FORMS calls this
  642.       * when the user moves the slider bar.
  643.       */
  644.      void SetVelocity(FL_OBJECT *obj, long val)
  645.      {
  646.        dt = fl_get_slider_value(VelocitySlider);
  647.      }
  648.  
  649.      /* Quit is the "Quit" button callback procedure; FORMS calls this
  650.       * when the user clicks the "Quit" button.
  651.       */
  652.      void Quit(FL_OBJECT *obj, long val)
  653.      {
  654.        exit(0);
  655.      }
  656.  
  657.      /* create_form_OurForm() creates the FORMS panel by calling a bunch of
  658.       * procedures in the FORMS library.  This code was generated
  659.       * automatically by the FORMS designer program; normally this code
  660.       * would be in a separate file which you would not edit by hand.  For
  661.       * simplicity of this example, however, we include this code here.
  662.       */
  663.      create_form_OurForm()
  664.      {
  665.        FL_OBJECT *obj;
  666.        FL_FORM *form;
  667.        OurForm = form = fl_bgn_form(FL_NO_BOX,380.0,120.0);
  668.        obj = fl_add_box(FL_UP_BOX,0.0,0.0,380.0,120.0,"");
  669.        VelocitySlider = obj = fl_add_valslider(FL_HOR_SLIDER,20.0,30.0,
  670.                                                340.0,40.0,"Velocity");
  671.          fl_set_object_lsize(obj,FL_LARGE_FONT);
  672.          fl_set_object_align(obj,FL_ALIGN_TOP);
  673.          fl_set_call_back(obj,SetVelocity,0);
  674.        obj = fl_add_button(FL_NORMAL_BUTTON,290.0,75.0,70.0,35.0,"Quit");
  675.          fl_set_object_lsize(obj,FL_LARGE_FONT);
  676.          fl_set_call_back(obj,Quit,0);
  677.        fl_end_form();
  678.      }
  679.  
  680.      main(argc, argv)        
  681.           char **argv;
  682.      {
  683.        int xdim, ydim;
  684.        float xmin, xmax, ymin, ymax, dx, dy, t;
  685.        int fdmask;
  686.        static struct timeval timeout = {0, 200000};
  687.  
  688.        xmin = ymin = -5;             /* Set x and y            */
  689.        xmax = ymax = 5;              /*    plot ranges         */
  690.        xdim = ydim = 24;             /* Set x and y resolution */
  691.        dt = 0.1;                     /* Time increment is 0.1  */
  692.  
  693.        /* Forms panel setup.
  694.         */
  695.        foreground();
  696.        create_form_OurForm();
  697.        fl_set_slider_bounds(VelocitySlider, 0.0, 1.0);
  698.        fl_set_slider_value(VelocitySlider, dt);
  699.        fl_show_form(OurForm, FL_PLACE_SIZE, TRUE, "Example 2");
  700.  
  701.  
  702.        /* Geomview setup.
  703.         */
  704.        printf("(geometry example { : foo })\n");
  705.        fflush(stdout);
  706.  
  707.        /* Loop until killed.
  708.         */
  709.        for (t=0; ; t+=dt) {
  710.          fdmask = (1 << fileno(stdin)) | (1 << qgetfd());
  711.          select(qgetfd()+1, &fdmask, NULL, NULL, &timeout);
  712.          fl_check_forms();
  713.          UpdateMesh(xmin, xmax, ymin, ymax, xdim, ydim, t);
  714.        }
  715.      }
  716.  
  717.      /* UpdateMesh sends one mesh iteration to Geomview
  718.       */
  719.      UpdateMesh(xmin, xmax, ymin, ymax, xdim, ydim, t)
  720.           float xmin, xmax, ymin, ymax, t;
  721.           int xdim, ydim;
  722.      {
  723.        int i,j;
  724.        float x,y, dx,dy;
  725.  
  726.        dx = (xmax-xmin)/(xdim-1);
  727.        dy = (ymax-ymin)/(ydim-1);
  728.  
  729.        printf("(read geometry { define foo \n");
  730.        printf("MESH\n");
  731.        printf("%1d %1d\n", xdim, ydim);
  732.        for (j=0, y = ymin; j<ydim; ++j, y += dy) {
  733.          for (i=0, x = xmin; i<xdim; ++i, x += dx) {
  734.            printf("%f %f %f\t", x, y, F(x,y,t));
  735.          }
  736.          printf("\n");
  737.        }
  738.        printf("})\n");
  739.        fflush(stdout);
  740.      }
  741.  
  742. The code begins by including some header files needed for the event loop
  743. and the FORMS library.  It then declares global variables for holding a
  744. pointer to the slider FORMS object and the velocity `dt'.  These
  745. are global because they are needed in the slider callback procedure
  746. `SetVelocity', which forms calls every time the user moves the
  747. slider bar. `SetVelocity' sets `dt' to be the new value of the
  748. slider.
  749.  
  750. `Quit' is the callback procedure for the *Quit* button;
  751. it provides a graceful way for the user to terminate the program.
  752.  
  753. The procedure `create_panel' calls a bunch of FORMS library
  754. procedures to set up the control panel with slider and button.  For more
  755. information on using FORMS to create interface panels see the FORMS
  756. documentation.  In particular, FORMS comes with a graphical panel
  757. designer that lets you design your panels interactively and generates
  758. code like that in `create_panel'.
  759.  
  760. This example's main program is similar to the previous example, but
  761. includes extra code to deal with setting up and managing the FORMS
  762. panel.  
  763.  
  764. To set up the panel we call the GL procedure `foreground' to cause
  765. the process to run in the foreground.  By default GL programs run in the
  766. background, and for various reasons external modules that use FORMS
  767. (which is based on GL) need to run in the foreground.  We then call
  768. `create_panel' to create the panel and `fl_set_slider_value'
  769. to set the initial value of the slider.  The call to `fl_show_form'
  770. causes the panel to appear on the screen.
  771.  
  772. The first three lines of the main loop, starting with 
  773.      fdmask = (1 << fileno(stdin)) | (1 << qgetfd());
  774. check for and deal with events in the panel.  The call to `select'
  775. imposes a delay on each pass through the main loop.  This call returns
  776. either after a delay of 1/5 second or when the next GL event occurs, or
  777. when data appears on standard input, whichever comes first.  The
  778. `timeout' variable specifies the amount of time to wait on this
  779. call; the first member (0 in this example) gives the number of seconds,
  780. and the second member (200000 in this example) gives the number of
  781. microseconds.  Finally, `fl_check_forms()' checks for and processes
  782. any FORMS events that have happened; in this case this means calling
  783. `SetVelocity' if the user has moved the slider or calling
  784. `Quit' if the user has clicked on the *Quit* button.
  785.  
  786. The purpose of the delay in the loop is to keep the program from using
  787. excessive amounts of CPU time running around its main loop when there
  788. are no events to be processed.  This is not so crucial in this example,
  789. and in fact may actually slow down the animation somewhat, but in
  790. general with external modules that have event loops it is important to
  791. do something like this because otherwise the module will needlessly take
  792. CPU cycles away from other running programs (such as Geomview!)  even
  793. when it isn't doing anything.
  794.  
  795. The last line of the main loop in this example, the call to
  796. `UpdateMesh', is the same as in the previous example.
  797.  
  798. 
  799. File: geomview  Node: Forms, Prev: Example2, Up: Modules, Next: Example3
  800.  
  801. The FORMS Library
  802. =================
  803.  
  804. Geomview itself is written using Mark Overmar's public domain FORMS
  805. library.  FORMS is a handy and relatively simple user interface toolkit
  806. for IRISes.  Many Geomview external modules, including the examples in
  807. this manual, use FORMS to create and manage control panels.
  808.  
  809. We distribute a version of the FORMS library with Geomview because it is
  810. necessary in order to compile Geomview and many of our modules.  If you
  811. use FORMS to write Geomview modules (or anything else, for that matter)
  812. you may use this copy.  The header file `forms.h' is in the
  813. `include' subdirectory, and the library file `libforms.a' is
  814. in the `lib/sgi' subdirectory (these are subdirectories of the
  815. Geomview distribution directory, `/u/gcg/ngrap' on the Geometry
  816. Center's system).  In particular, you can link the example modules in
  817. this manual using this copy.
  818.  
  819. FORMS is available via ftp on the Internet from a variety of sites,
  820. including `cs.ruu.nl' or `glaurung.physics.mcgill.ca'.  It
  821. comes with source code and extensive documentation.
  822.  
  823. If you wish you may use any other interface toolkit instead of FORMS in
  824. an external module.  We chose FORMS because it is free and relatively
  825. simple.
  826.  
  827.  
  828. 
  829. File: geomview  Node: Example3, Prev: Forms, Up: Modules, Next: Module Installation
  830.  
  831. Example 3: External Module with Bi-Directional Communication
  832. ============================================================
  833.  
  834. The previous two example modules simply send commands to Geomview and do
  835. not receive anything from Geomview.  This section describes a module
  836. that communicates in both directions.  There are two types of
  837. communication that can go from Geomview to an external module.  This
  838. example shows *asynchronous* communication --- the module needs to
  839. be able to respond at any moment to expressions that Geomview may emit
  840. which inform the module of some change of state within Geomview.
  841.  
  842. (The other type of communication is *synchronous*, where a module
  843. sends a request to Geomview for some piece of information and waits for
  844. a response to come back before doing anything else.  The main gcl
  845. command for requesting information of this type is `write'.  This
  846. module does not do any synchronous communication.)
  847.  
  848. In ansynchronous communication, Geomview sends expressions that are
  849. essentially echoes of gcl commands.  The external module sends
  850. Geomview a command expressing interest in a certain command, and then
  851. every time Geomview executes that command, the module receives a copy of
  852. it.  This happens regardless of who sent the command to Geomview; it can
  853. be the result of the user doing something with a Geomview panel, or
  854. it may have come from another module or from a file that Geomview reads.
  855. This is how a module can find out about and act on things that happen in
  856. Geomview.
  857.  
  858. This example uses the OOGL lisp library to parse and act on the
  859. expressions that Geomview writes to the module's standard input.  This
  860. library is actually part of Geomview itself --- we wrote the library in
  861. the process of implementing gcl.  It is also convenient to use it in
  862. external modules that must understand a of subset of gcl ---
  863. specifically, those commands that the module has expressed interest in.
  864.  
  865. This example shows how a module can receive user pick events, i.e.
  866. when the user clicks the right mouse button with the cursor over a geom
  867. in a Geomview camera window.  When this happens Geomview generates an
  868. internal call to a procedure called `pick'; the arguments to the
  869. procedure give information about the pick, such as what object was
  870. picked, the coordinates of the picked point, etc.  If an external module
  871. has expressed interest in calls to `pick', then whenever
  872. `pick' is called Geomview will echo the call to the module's
  873. standard input.  The module can then do whatever it wants with the pick
  874. information.
  875.  
  876. This module is the same as the *Nose* module that comes with
  877. Geomview.  Its purpose is to illustrate picking.  Whenever you pick on a
  878. geom by clicking the right mouse button on it, the module draws a little
  879. box at the spot where you clicked.  Usually the box is yellow.  If you
  880. pick a vertex, the box is colored magenta.  If you pick a point on an
  881. edge of an object, the module will also highlight the edge by drawing
  882. cyan boxes at its endpoints and drawing a yellow line along the edge.
  883.  
  884. Note that in order for this module to actually do anything you must have
  885. a geom loaded into Geomview and you must click the right mouse button
  886. with the cursor over a part of the geom.
  887.  
  888.      /*
  889.       * example3.c: external module with bi-directional communication
  890.       *
  891.       * This example module is distributed with the Geomview manual.
  892.       * If you are not reading this in the manual, see the "External
  893.       * Modules" chapter of the manual for an explanation.
  894.       *
  895.       * This module is the same as the "Nose" program that is distributed
  896.       * with Geomview.  It illustrates how a module can find out about
  897.       * and respond to user pick events in Geomview.  It draws a little box
  898.       * at the point where a pick occurrs.  The box is yellow if it is not
  899.       * at a vertex, and magenta if it is on a vertex.  If it is on an edge,
  900.       * the program also marks the edge.
  901.       *
  902.       * To compile:
  903.       *
  904.       *   cc -I/u/gcg/ngrap/include -g -o example3 example3.c \
  905.       *      -L/u/gcg/ngrap/lib/sgi -loogl -lm
  906.       *
  907.       * If you are not on the Geometry Center's system you should replace
  908.       * "/u/gcg/ngrap" above with the pathname of the Geomview distribution
  909.       * directory on your system.
  910.       */
  911.  
  912.      #include <stdio.h>
  913.      #include "lisp.h"               /* We use the OOGL lisp library */
  914.      #include "pickfunc.h"           /* for PICKFUNC below */
  915.      #include "3d.h"                 /* for 3d geometry library */
  916.  
  917.      /* boxstring gives the OOGL data to define the little box that
  918.       * we draw at the pick point.  NOTE:  It is very important to
  919.       * have a newline at the end of the OFF object in this string.
  920.       */
  921.      char boxstring[] = "\
  922.      INST\n\
  923.      transform\n\
  924.      .04 0 0 0\n\
  925.      0 .04 0 0\n\
  926.      0 0 .04 0\n\
  927.      0 0 0 1\n\
  928.      geom\n\
  929.      OFF\n\
  930.      8 6 12\n\
  931.      \n\
  932.      -.5 -.5 -.5     # 0   \n\
  933.      .5 -.5 -.5      # 1   \n\
  934.      .5  .5 -.5      # 2   \n\
  935.      -.5  .5 -.5     # 3   \n\
  936.      -.5 -.5  .5     # 4   \n\
  937.      .5 -.5  .5      # 5   \n\
  938.      .5  .5  .5      # 6   \n\
  939.      -.5  .5  .5     # 7   \n\
  940.      \n\
  941.      4 0 1 2 3\n\
  942.      4 4 5 6 7\n\
  943.      4 2 3 7 6\n\
  944.      4 0 1 5 4\n\
  945.      4 0 4 7 3\n\
  946.      4 1 2 6 5\n";
  947.  
  948.      progn()
  949.      {
  950.        printf("(progn\n");
  951.      }
  952.  
  953.      endprogn()
  954.      {
  955.        printf(")\n");
  956.        fflush(stdout);
  957.      }
  958.  
  959.      Initialize()
  960.      {
  961.        extern LObject *Lpick();  /* This is defined by PICKFUNC below but must */
  962.                        /* be used in the following LDefun() call */
  963.        LInit();
  964.        LDefun("pick", Lpick, NULL);
  965.  
  966.        progn(); {
  967.          /* Define handle "littlebox" for use later
  968.           */
  969.          printf("(read geometry { define littlebox { %s }})\n", boxstring);
  970.  
  971.          /* Express interest in pick events; see Geomview manual for explanation.
  972.           */
  973.          printf("(interest (pick world * * * * nil nil nil nil nil))\n");
  974.  
  975.          /* Define "pick" object, initially the empty list (= null object).
  976.           * We replace this later upon receiving a pick event.
  977.           */
  978.          printf("(geometry \"pick\" { LIST } )\n");
  979.  
  980.          /* Make the "pick" object be non-pickable.
  981.           */
  982.          printf("(pickable \"pick\" no)\n");
  983.  
  984.          /* Turn off normalization, so that our pick object will appear in the
  985.           * right place.
  986.           */
  987.          printf("(normalization \"pick\" none)\n");
  988.  
  989.          /* Don't draw the pick object's bounding box.
  990.           */
  991.          printf("(bbox-draw \"pick\" off)\n");
  992.  
  993.        } endprogn();
  994.      }
  995.  
  996.      /* The following is a macro call that defines a procedure called
  997.       * Lpick().  The reason for doing this in a macro is that that macro
  998.       * encapsulates a lot of necessary stuff that would be the same for
  999.       * this procedure in any program.  If you write a Geomview module that
  1000.       * wants to know about user pick events you can just copy this macro
  1001.       * call and change the body to suit your needs; the body is the last
  1002.       * argument to the macro and is delimited by curly braces.
  1003.       *
  1004.       * The first argument to the macro is the name of the procedure to
  1005.       * be defined, "Lpick".
  1006.       *
  1007.       * The next two arguments are numbers which specify the sizes that
  1008.       * certain arrays inside the body of the procedure should have.
  1009.       * These arrays are used for storing the face and path information
  1010.       * of the picked object.  In this module we don't care about this
  1011.       * information so we declare them to have length 1, the minimum
  1012.       * allowed.
  1013.       *
  1014.       * The last argument is a block of code to be executed when the module
  1015.       * receives a pick event.  In this body you can refer to certain local
  1016.       * variables that hold information about the pick.  For details see
  1017.       * Example 3 in the Extenal Modules chapter of the Geomview manual.
  1018.       */
  1019.      PICKFUNC(Lpick, 1, 1,
  1020.      {           
  1021.        handle_pick(pn>0, &point, vn>0, &vertex, en>0, edge);
  1022.      })
  1023.  
  1024.      handle_pick(picked, p, vert, v, edge, e)
  1025.           int picked;                /* was something actually picked?     */
  1026.           int vert;                  /* was the pick near a vertex?        */
  1027.           int edge;                  /* was the pick near an edge?         */
  1028.           HPoint3 *p;                /* coords of pick point               */
  1029.           HPoint3 *v;                /* coords of picked vertex            */
  1030.           HPoint3 e[2];              /* coords of endpoints of picked edge */
  1031.      {
  1032.        Normalize(&e[0]);             /* Normalize makes 4th coord 1.0 */
  1033.        Normalize(&e[1]);
  1034.        Normalize(p);
  1035.        progn(); {
  1036.          if (!picked) {
  1037.            printf("(geometry \"pick\" { LIST } )\n");
  1038.          } else {
  1039.            /*
  1040.             * Put the box in place, and color it magenta if it's on a vertex,
  1041.             * yellow if not.
  1042.             */
  1043.            printf("(xform-set pick { 1 0 0 0  0 1 0 0  0 0 1 0  %g %g %g 1 })\n",
  1044.                   p->x, p->y, p->z);
  1045.            printf("(geometry \"pick\"\n");
  1046.            if (vert) printf("{ appearance { material { diffuse 1 0 1 } }\n");
  1047.            else printf("{ appearance { material { diffuse 1 1 0 } }\n");
  1048.            printf("  { LIST { :littlebox }\n");
  1049.       
  1050.            /*
  1051.             * If it's on an edge and not a vertex, mark the edge
  1052.             * with cyan boxes at the endpoins and a black line
  1053.             * along the edge.
  1054.             */
  1055.            if (edge && !vert) {
  1056.              e[0].x -= p->x; e[0].y -= p->y; e[0].z -= p->z;
  1057.              e[1].x -= p->x; e[1].y -= p->y; e[1].z -= p->z;
  1058.              printf("{ appearance { material { diffuse 0 1 1 } }\n\
  1059.        LIST\n\
  1060.         { INST transform 1 0 0 0 0 1 0 0 0 0 1 0 %f %f %f 1 geom :littlebox }\n\
  1061.         { INST transform 1 0 0 0 0 1 0 0 0 0 1 0 %f %f %f 1 geom :littlebox }\n\
  1062.         { VECT\n\
  1063.                1 2 1\n\
  1064.                2\n\
  1065.                1\n\
  1066.                %f %f %f\n\
  1067.                %f %f %f\n\
  1068.                1 1 0 1\n\
  1069.         }\n\
  1070.        }\n",
  1071.                     e[0].x, e[0].y, e[0].z,
  1072.                     e[1].x, e[1].y, e[1].z,
  1073.                     e[0].x, e[0].y, e[0].z,
  1074.                     e[1].x, e[1].y, e[1].z);
  1075.            }
  1076.            printf("    }\n  }\n)\n");
  1077.          }
  1078.  
  1079.        } endprogn();
  1080.  
  1081.      }
  1082.  
  1083.      Normalize(HPoint3 *p)
  1084.      {
  1085.        if (p->w != 0) {
  1086.          p->x /= p->w;
  1087.          p->y /= p->w;
  1088.          p->z /= p->w;
  1089.          p->w = 1;
  1090.        }
  1091.      }
  1092.  
  1093.      main()
  1094.      {
  1095.        Lake *lake;
  1096.        LObject *lit, *val;
  1097.        extern char *getenv();
  1098.  
  1099.        Initialize();
  1100.  
  1101.        lake = LakeDefine(stdin, stdout, NULL);
  1102.        while (!feof(stdin)) {
  1103.  
  1104.          /* Parse next lisp expression from stdin.
  1105.           */
  1106.          lit = LSexpr(lake);
  1107.  
  1108.          /* Evaluate that expression; this is where Lpick() gets called.
  1109.           */
  1110.          val = LEval(lit);
  1111.  
  1112.          /* Free the two expressions from above.
  1113.           */
  1114.          LFree(lit);
  1115.          LFree(val);
  1116.        }
  1117.      }
  1118.  
  1119. The code begins by defining procedures `progn()' and
  1120. `endprogn()' which begin and end a Geomview `progn' group.
  1121. The purpose of the Geomview `progn' command is to group commands
  1122. together and cause Geomview to execute them all at once, without
  1123. refreshing any graphics windows until the end.  It is a good idea to
  1124. group blocks of commands that a module sends to Geomview like this so
  1125. that the user sees their cumulative effect all at once.
  1126.  
  1127. Procedure `Initialize()' does various things needed at program
  1128. startup time.  It initializes the lisp library by calling
  1129. `LInit()'.  Any program that uses the lisp library should call this
  1130. once before calling any other lisp library functions.  It then calls
  1131. `LDefun' to tell the library about our `pick' procedure, which
  1132. is defined further down with a call to the `DEFPICKFUNC' macro.
  1133. Then it sends a bunch of setup commands to Geomview, grouped in a
  1134. `progn' block.  This includes defining a handle called `littlebox'
  1135. that stores the geometry of the little box.  Next it sends the command
  1136.  
  1137.      (interest (pick world * * * * nil nil nil nil nil))
  1138.  
  1139. which tells Geomview to notify us when a pick event happens.
  1140.  
  1141. The syntax of this `interest' statement merits some explanation.
  1142. In general `interest' takes one argument which is a (parenthesized)
  1143. expression representing a Geomview function call.  It specifies a type
  1144. of call that the module is interested in knowing about.  The arguments
  1145. can be any particular argument values, or the special symbols `*'
  1146. or `nil'.  For example, the first argument in the `pick'
  1147. expression above is `world'.  This means that the module is
  1148. interested in calls to `pick' where the first argument, which
  1149. specifies the coordinate system, is `world'.  A `*' is like a
  1150. wild-card; it means that the module is interested in calls where the
  1151. corresponding argument has any value.  The word `nil' is like
  1152. `*', except that the argument's value is not reported to the
  1153. module.  This is useful for cutting down on the amount of data that must
  1154. be transmitted in cases where there are arguments that the module
  1155. doesn't care about.
  1156.  
  1157. The second, third, fourth, and fifth arguments to the `pick'
  1158. command give the name, pick point coordinates, vertex coordinates, and
  1159. edge coordinates of a pick event.  We specify these by `*''s above.
  1160. The remaining five arguments to the `pick' command give other
  1161. information about the pick event that we do not care about in this
  1162. module, so we specify these with `nil''s.  For the details of the
  1163. arguments to `pick', *Note GCL::.
  1164.  
  1165. The `geometry' statement defines a geom called `pick' that is
  1166. initially an empty list, specified as ` { LIST } '; this is the
  1167. best way of specifying a null geom.  The module will replace this with
  1168. something useful by sending Geomview another `geometry' command
  1169. when the user picks something.  Next we arrange for the `pick'
  1170. object to be non-pickable, and turn normalization off for it so that
  1171. Geomview will display it in the size and location where we put it,
  1172. rather than resizing and relocating it to fit into the unit cube.
  1173.  
  1174. The next function in the file, `Lpick', is defined with a strange
  1175. looking call to a macro called `PICKFUNC', defined in the header
  1176. file `pickfunc.h'.  This is the function for handling pick events.
  1177. The reason we provide a macro for this is that that macro encapsulates a
  1178. lot of necessary stuff that would be the same for the pick-handling
  1179. function in any program.  If you write a Geomview module that wants to
  1180. know about user pick events you can just copy this macro call and change
  1181. it to suit yours needs.
  1182.  
  1183. In general the syntax for `PICKFUNC' is
  1184.      PICKFUNC(NAME, MAXFACEVERTS, MAXPATHLEN, BLOCK)
  1185. where NAME is the name of the procedure to be defined, in this
  1186. case `Lpick'.  The next two arguments, MAXFACEVERTS and
  1187. MAXPATHLEN, give the sizes to be used for declaring two local
  1188. variable arrays in the body of the procedure.  These arrays are for
  1189. storing information about the picked face and the picked primitive's
  1190. path.  In this module we don't care about this information (it
  1191. corresponds to some of the things masked out by the `nil''s in the
  1192. `interest' call above) so we specify 1, the minimum allowable, for
  1193. both of these.  The last argument, BLOCK, is a block of code to be
  1194. executed when a pick event occurs.  The BLOCK should be delimited
  1195. by curly braces.  The code in your BLOCK should not include
  1196. any `return' statements.
  1197.  
  1198. `PICKFUNC' declares certain local variables in the body of the
  1199. procedure.  When the module receives a `(pick ...)' statement
  1200. from Geomview, the procedure assigns values to these variables based on
  1201. the information in the `pick' call.  (Variables corresponding to
  1202. `nil''s in the `(interest (pick ...))' are not given
  1203. values.)
  1204. These variables are:
  1205.  
  1206. `char *coordsys;'
  1207.      A string specifying the coordinate system in which coordinates are
  1208.      given.  In this example, this will always be `world' because
  1209.      of the `interest' call above.
  1210.  
  1211. `char *id;'
  1212.      A string specifying the name of the picked geom.
  1213.  
  1214. `HPoint3 point; int pn;'
  1215.      `point' is an `HPoint3' structure giving the coordinates of
  1216.      the picked point.  `HPoint3' is a homogeneous point coordinate
  1217.      representation eqivalent to an array of 4 floats.  `pn' tells how
  1218.      many coordinates have been written into this array; it will always be
  1219.      either 0 or 4.  A value of zero means no point was picked, i.e. the user
  1220.      clicked the right mouse button while the cursor was not pointing at a
  1221.      geom.
  1222.  
  1223. `HPoint3 vertex; int vn;'
  1224.      `vertex' is an `HPoint3' structure giving the coordinates of
  1225.      the picked vertex, if the pick point was near a vertex.  `vn' tells
  1226.      how many coordinates have been written into this array; it will always
  1227.      be either 0 or 4.  A value of zero means the pick point was not near a
  1228.      vertex.
  1229.  
  1230. `HPoint3 edge[2]; int en;'
  1231.      `edge' is an array of two `HPoint3' structures giving the
  1232.      coordinates of the endpoints of the picked edge, if the pick point was
  1233.      near an edge.  `en' tells how many coordinates have been written
  1234.      into this array; it will always be either 0 or 8.  A value of zero means
  1235.      the pick point was not near an edge.
  1236.  
  1237.  
  1238. In this example module, the remaining variables will never be given
  1239. values because their values in the `interest' statement were
  1240. specified as `nil'.   
  1241.  
  1242.  
  1243. `HPoint3 face[MAXFACEVERTS]; int fn;'
  1244.      `face' is an array of MAXFACEVERTS `HPoint3''s;
  1245.      MAXFACEVERTS is the value specified in the `PICKFUNC' call.
  1246.      `face' gives the coordinates of the vertices of the picked face.
  1247.      `fn' tells how many coordinates have been written into this array;
  1248.      it will always be a multiple of 4 and will be at most
  1249.      4*MAXFACEVERTS.  A value of zero means the pick point was not near
  1250.      a face.
  1251.  
  1252. `HPoint3 ppath[MAXPATHLEN; int ppn;'
  1253.      `ppath' is an array of MAXPATHLEN `int''s;
  1254.      MAXPATHLEN is the value specified in the `PICKFUNC' call.
  1255.      `ppath' gives the path through the OOGL heirarchy to the picked
  1256.      primitive.  `pn' tells how many integers have been written into
  1257.      this array; it will be at most MAXPATHLEN.  A path of {3,1,2},
  1258.      for example, means that the picked primitive is "subobject number 2
  1259.      of subobject number 1 of object 3 in the world".
  1260.  
  1261. `int vi;'
  1262.      `vi' gives the index of the picked vertex in the picked primitive,
  1263.      if the pick point was near a vertex.
  1264.  
  1265. `int ei[2]; int ein'
  1266.      The `ei' array gives the indices of the endpoints of the picked
  1267.      edge, if the pick point was near a vertex.  `ein' tells how many
  1268.      integers were written into this array.  It will always be either 0 or 2;
  1269.      a value of 0 means the pick point was not near an edge.
  1270.  
  1271. `int fi;'
  1272.      `fi' gives the index of the picked face in the picked primitive, if
  1273.      the pick point was near a face.
  1274.  
  1275.  
  1276. The `handle_pick' procedure actually does the work of dealing with
  1277. the pick event.  It begins by normalizing the homogeneous coordinates
  1278. passed in as arguments so that we can assume the fourth coordinate is 1.
  1279. It then sends gcl commands to define the `pick' object to be
  1280. whatever is appropriate for the kind of pick recieved.  See *Note OOGL File Formats::, and *Note GCL::, for an explanation of the
  1281. format of the data in these commands.
  1282.  
  1283. The main program, at the bottom of the file, first calls
  1284. `Initialize()'.  Next, the call to `LakeDefine' defines the
  1285. `Lake' that the lisp library will use.  A `Lake' is a
  1286. structure that the lisp library uses internally as a type of
  1287. communiation vehicle.  (It is like a unix stream but more general, hence
  1288. the name.)  This call to `LakeDefine' defines a `Lake'
  1289. structure for doing I/O with `stdin' and `stdout'.  The third
  1290. argument to `LakeDefine' should be `NULL' for external modules
  1291. (it is used by Geomview).  Finally, the program enters its main loop
  1292. which parses and evaluates expressions from standard input.
  1293.  
  1294. 
  1295.